import {observable, autorun, observe, computed, reaction, action, configure, runInAction} from "mobx";

// mobx 全局配置
configure({
    // 强制使用 action方法的模式，
    enforceActions:"observed"
})

const query = () => {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(12000);
        }, 1000);
    });
};

class Store {
    // @observable  把状态变为可监测的，只有这样，以后基于 autorun / @observer 等监测机制才会生效! !
    @observable x = 10
    @observable y = 20
    @observable count = 3
    @observable price = 120

    // @computed    创建一个计算缓存的计算属性
    @computed get total() {
        return this.count * this.price
    }
    // @action      修饰函数的装饰器，让函数中的状态更改为"异步批处理器"
    // @action.bound    保证函数无论如何执行，函数中的this都是Store的实例
    @action change(){
        this.x = 1000
        this.y = 2000
    }

    @action ayncChange(){
        let res = 0;
        query().then(res=>{
            runInAction(() => {
                this.x = res;
            });
        })

    }
}

let store = new Store

// reaction: 和autorun一样，都是监听器，提供更细粒化的状态检测(默认是初始化不会执行的)

// reaction(
//     () => [store.x, store.total],
//     () => {
//         console.log('reaction', store.x, store.total)
//     }
// )

autorun(() => {
    // 首先会立即执行一次，自动建立起依赖监测(监测用到的状态): 当依赖的状态值发生改变，callback会重新执行
    console.log('autorun', store.total, store.x, store.y)
})
setTimeout(() => {
    // 修改多个状态，会让 autorun 执行多次
    // store.x = 1000 // total计算属性不会重新执行，用之前缓存的结果
    // store.y = 2000
    // store.count = 10 // total计算属性需要重新执行，计算出新的值
    // store.change()
    // 基于 runInAction 可以实现和 @action 一模一样的效果
    // runInAction(()=>{
    //     store.x = 1000
    //     store.y = 2000
    // })
    store.ayncChange()
}, 1000)

// 经过observable处理后的数据，是基于ES6Proxy做过数据劫持的，这样我们后期修改状态值，就可以在SETTER函政中去做
// 些特殊处理，例如:把依赖其值的监听客触发执行。

// let obj = observable({
//     x: 10,
//     y: 20
// })
// console.log(obj)
//
// // 创建监听器，对对象进行监听，当对象中的某个成员发生改变，触发回调函数执行前提是: 对象是基于 observable 修饰的，把其变为可监听的
// observe(obj, change => {
//     console.log(change)
// })
//
// obj.x = 200
//
//
//
// let x = observable.box(10)
// x.set(1000)
// console.log(x) // ObservableValue{...}
// console.log(x.get()) // 1000


// ES6中 proxy
// 对当前某个对象进行数据劫持和代理
// let obj = {
//     x: 10,
//     y: 20
// }
// let proxyObj = new Proxy(obj, {
//     get(target, key) {
//         console.log("GETTER", target, key)
//         return target[key]
//     },
//     set(target, key, value) {
//         console.log("SETTER", target, key, value)
//         target[key] = value
//         return true
//     }
// })
// console.log(proxyObj);
// console.log(proxyObj.x);
// proxyObj.x = 1000
// console.log(proxyObj.x)